<?php
/**
 * Redis
 *
 */
class Helper_Redis
{
    protected $flag = 0;	//默认Flag
    protected $expire = 0;	//默认有效期(无限期)

    protected $hasOld = false;	//是否有老集群

    protected $config;	//当前集群配置
    protected $link = array();	//当前集群连接池
    protected $serverSum = 1;	//当前集群数量
    protected $serverNow = -1;	//当前集群正使用的连接

    protected $oldConfig;	//老集群配置
    protected $oldLink = array();	//老集群连接池
    protected $oldServerSum = 1;	//老集群数量
    protected $oldServerNow = -1;	//老集群正使用的连接

    public static $singletonObjects = array();

    /**
     * 单例
     * 
     * @param string $group
     * @return Helper_Reids
     * @throws Exception
     */
    public static function getInstance( $group )
    {
        if( isset( self::$singletonObjects[ $group ] ) )
        {
            return self::$singletonObjects[ $group ];
        }

        $redisConfig = & Common::getConfig( 'redisConfig' );
        if( empty( $redisConfig[ $group ] ) )
        {
            throw new AppException( 1 , 'redisConfig:'.$redisConfig[ $group ] );
        }

        self::$singletonObjects[ $group ] = new self( $redisConfig[ $group ] );
        return self::$singletonObjects[ $group ];
    }

    /**
     * 初始化配置
     *
     * @param array $config	//集群配置
     */
    public function __construct( $config )
    {
        if( isset( $config['current'] ) && isset( $config['old'] ) )
        {
        	$this->config = $config['current'];
    		$this->serverSum = count( $config['current'] );

        	$this->oldConfig = $config['old'];
        	$this->oldServerSum = count( $config['old'] );

        	$this->hasOld = true;
        }
        else
        {
        	$this->config = $config;
        	$this->serverSum = count( $config );
        }
    }

    /**
     * 切换当前集群连接
     *
     * @param string $key
     * @param int $serverId
     */
    protected function selectServer( $key = '' , $serverId = false )
    {
        $serverId = ( $serverId === false ) ? intval( $key ) % $this->serverSum : $serverId % $this->serverSum;
        if( ( $this->serverNow != $serverId ) && ( !isset( $this->link[ $serverId ] ) ) )
        {
            $this->link[ $serverId ] = new Redis();
            $this->link[ $serverId ]->connect( $this->config[ $serverId ][ 'host' ] , $this->config[ $serverId ]['port'] );
        }

        $this->serverNow = $serverId;
    }

    /**
    * 切换老集群连接
    *
    * @param string $key
    * @param int $serverId
    */
    protected function selectOldServer( $key = '' , $serverId = false )
    {
        $serverId = ( $serverId === false ) ? intval( $key ) % $this->oldServerSum : $serverId % $this->oldServerSum;
        if( ( $this->oldServerNow != $serverId ) && ( !isset( $this->oldLink[ $serverId ] ) ) )
        {
            $this->oldLink[ $serverId ] = new Redis();
            $this->oldLink[ $serverId ]->connect( $this->oldConfig[ $serverId ][ 'host' ] , $this->oldConfig[ $serverId ]['port'] );
        }

        $this->oldServerNow = $serverId;
    }

    /**
    * 设置到缓存
    *
    * @param string $key
    * @param mixed
    * @param int $expire
    * @param int $flag
    * @param int $serverId
    * @return boolean
    */
    public function set( $key , $value , $expire = 0 , $serverId = false )
    {
        $value = json_encode( $value );
        $expire = ( $expire > 0 ) ? $expire : $this->expire;
        $this->selectServer( $key , $serverId );
        if( $expire > 0 )
        {
            $result = $this->link[ $this->serverNow ]->setex( $key , $expire , $value );
        }
        else
        {
            $result = $this->link[ $this->serverNow ]->set( $key , $value );
        }
        
        return $result;
    }

    /**
     * 获取缓存数据
     * 		支持单键获取时平滑扩容
     *  	支持多键获取
     *
     * @param string $key
     * @param int $serverId
     * @return mixed
     */
    public function get( $key , $serverId = false )
    {
    	//获取没有指定服务器ID的多键
//    	if( is_array( $key ) && $serverId == false )
//    	{
//    		$groups = array();
//			foreach ( $key as $item )
//			{
//				$serverId = intval( $item ) % $this->serverSum;
//				$groups[ $serverId ][] = $item;
//			}
//
//			$data = array();
//			foreach ( $groups as $serverId => $item )
//			{
//				$this->selectServer( '' , $serverId );
//				$temp = $this->link[ $this->serverNow ]->getMultiple( $item );
//				if ( !empty( $temp ) )
//				{
//					$data = $data + $temp;
//				}
//			}
//
//			//若开启平滑扩容,则获取老集群数据
//			if( $this->hasOld )
//			{
//				$remainKeys = array_diff( $key , array_keys( $data ) );
//				if( $remainKeys )
//				{
//					$groups = array();
//					foreach ( $remainKeys as $item )
//					{
//						$serverId = intval( $item ) % $this->oldServerSum;
//						$groups[ $serverId ][] = $item;
//					}
//
//					foreach ( $groups as $serverId => $item )
//					{
//						$this->selectOldServer( '' , $serverId );
//						$temp = $this->oldLink[ $this->oldServerNow ]->getMulti( $item );
//						if ( !empty( $temp ) )
//						{
//							$data = $data + $temp;
//						}
//					}
//				}
//			}
//
//			return $data;
//    	}

        $this->selectServer( $key , $serverId );
//        if( is_array( $key ) )
//        {
//        	return $this->link[ $this->serverNow ]->getMulti( $key );
//        }
//        else
//        {
        	$info = $this->link[ $this->serverNow ]->get( $key );

        	//平滑扩容迁移操作
        	if( $info === false && $this->hasOld )
        	{
        		$this->selectOldServer( $key );
        		$info = $this->oldLink[ $this->oldServerNow ]->get( $key );
        		if( $info !== false )
        		{
        			$this->add( $key , $info , 0 );
    				$this->oldLink[ $this->oldServerNow ]->delete( $key );
        		}
        	}

            if( $info )
            {
                $info = json_decode( $info , true );
            }

        	return $info;
//        }
    }
    
    /**
     * 返回测试环境下redis里所有的key数组
     * 
     * @param string $key
     * @return array
     */
    public function getKeys( $key = '' )
    {
        $this->selectServer( $key );
        return $this->link[ $this->serverNow ]->keys( $key );
    }

    /**
     * 递增缓存
     *
     * @param string $key
     * @param int $value
     * @return boolean
     */
    public function incr( $key , $value = 1 )
    {
        $this->selectServer( $key );
        return $this->link[ $this->serverNow ]->incrby( $key , $value );
    }

    /**
     * 递减缓存
     *
     * @param string $key
     * @param int $value
     * @return boolean
     */
    public function decr( $key , $value = 1 )
    {
        $this->selectServer( $key );
        return $this->link[ $this->serverNow ]->decrBy( $key , $value );
    }
    
    public function rpush( $key , $value )
    {
        $this->selectServer( $key );
        if( is_array( $value ) )
        {
            $value = json_encode( $value );
        }
            
        return $this->link[ $this->serverNow ]->rpush( $key , $value );
    }
    
    public function lpop( $key )
    {
        $this->selectServer( $key );
        $value = $this->link[ $this->serverNow ]->lpop( $key );
        return json_decode( $value , true );
    }

    /**
     * 删除缓存
     *
     * @param string $key
     * @param int $serverId
     * @return boolean
     */
    public function delete( $key , $serverId = false )
    {
        $this->selectServer( $key , $serverId );
        return $this->link[ $this->serverNow ]->delete( $key );
    }

    /**
     * 获取错误状态
     * @return	int
     */
    public function getErrorCode()
    {
    	return $this->link[ $this->serverNow ]->getResultCode();
    }

    /**
     * 获取错误信息
     * @return	string
     */
    public function getErrorMessage()
    {
    	return $this->link[ $this->serverNow ]->getResultMessage();
    }
}